//(c) Copyright 2012 Hewlett-Packard Development Company, L.P.
//
//Confidential computer software. Valid license from HP required for possession, use or copying.
//Consistent with FAR 12.211 and 12.212, Commercial Computer Software, Computer Software Documentation, 
//and Technical Data for Commercial Items are licensed to the U.S. Government under vendor's standard commercial license.

package com.algorithms;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class DeadLock {

	// Object used for FLAT lock
	private final Object sharedObject = new Object();
	// ReentrantReadWriteLock used for WRITE & READ locks
	private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

	/**
	 *  Execution pattern #1
	 */
	public void executeTask1() {

		// 1. Attempt to acquire a ReentrantReadWriteLock READ lock
		lock.writeLock().lock();
		//lock.readLock().lock(); //jstack can NOT detect the dead lock if the readLock() used here.

		// Wait 2 seconds to simulate some work...
		try {
			Thread.sleep(2000);
		} catch (Throwable any) {
		}

		try {
			// 2. Attempt to acquire a Flat lock...
			synchronized (sharedObject) {
			}
		}
		// Remove the READ lock
		finally {
			lock.writeLock().unlock();
			//lock.readLock().unlock();
		}
		System.out.println("executeTask1() :: Work Done!");
	}

	/**
	 *  Execution pattern #2
	 */
	public void executeTask2() {
		// 1. Attempt to acquire a Flat lock
		synchronized (sharedObject) {

			// Wait 2 seconds to simulate some work...
			try {
				Thread.sleep(2000);
			} catch (Throwable any) {
			}

			// 2. Attempt to acquire a WRITE lock                   
			lock.writeLock().lock();

			try {
				// Do nothing
			}

			// Remove the WRITE lock
			finally {
				lock.writeLock().unlock();
			}
		}
		System.out.println("executeTask2() :: Work Done!");
	}

	public ReentrantReadWriteLock getReentrantReadWriteLock() {
		return lock;
	}

	public static void main(String[] args) {
		final DeadLock dl = new DeadLock();
		Thread t1 = new Thread() {
			public void run() {
				dl.executeTask1();
			}
		};

		Thread t2 = new Thread() {
			public void run() {
				dl.executeTask2();
			}
		};

		System.out.println("Started");

		t1.start();
		t2.start();
		try {
			t1.join();
			t2.join();
		} catch (InterruptedException e) {

		}

		System.out.println("Finished.");

	}

}
